#ifndef _WX_HTMLWIN_H_
#define _WX_HTMLWIN_H_

#include "wx/defs.h"
#include "wx/window.h"
#include "wx/scrolwin.h"
#include "wx/config.h"
#include "wx/stopwatch.h"
#include "wx/html/winpars.h"
#include "wx/html/htmlcell.h"
#include "wx/filesys.h"
#include "wx/html/htmlfilt.h"
#include "wx/filename.h"
#include "wx/bitmap.h"

class wxHtmlProcessor;
class wxHtmlWinModule;
class wxHtmlHistoryArray;
class wxHtmlProcessorList;
class wxHtmlWinAutoScrollTimer;
class wxHtmlCellEvent;
class wxHtmlLinkEvent;

#define wxHW_SCROLLBAR_NEVER    0x0002
#define wxHW_SCROLLBAR_AUTO     0x0004
#define wxHW_NO_SELECTION       0x0008

#define wxHW_DEFAULT_STYLE      wxHW_SCROLLBAR_AUTO

enum wxHtmlOpeningStatus {
  wxHTML_OPEN,
  wxHTML_BLOCK,
  wxHTML_REDIRECT
};

class wxHtmlWindowInterface {
  public:
    wxHtmlWindowInterface() {}
    virtual ~wxHtmlWindowInterface() {}
    virtual void SetHTMLWindowTitle( const wxString& title ) = 0;
    virtual void OnHTMLLinkClicked( const wxHtmlLinkInfo& link ) = 0;
    virtual wxHtmlOpeningStatus OnHTMLOpeningURL( wxHtmlURLType type,const wxString& url,wxString *redirect ) const = 0;
    virtual wxPoint HTMLCoordsToWindow( wxHtmlCell *cell,const wxPoint& pos ) const = 0;
    virtual wxWindow* GetHTMLWindow() = 0;
    virtual wxColour GetHTMLBackgroundColour() const = 0;
    virtual void SetHTMLBackgroundColour( const wxColour& clr ) = 0;
    virtual void SetHTMLBackgroundImage( const wxBitmap& bmpBg ) = 0;
    virtual void SetHTMLStatusText( const wxString& text ) = 0;
    enum HTMLCursor {
      /// Standard mouse cursor (typically an arrow)
      HTMLCursor_Default,
      /// Cursor shown over links
      HTMLCursor_Link,
      /// Cursor shown over selectable text
      HTMLCursor_Text
    };

    /**
        Returns mouse cursor of given @a type.
    */
    virtual wxCursor GetHTMLCursor( HTMLCursor type ) const = 0;
};

class wxHtmlWindowMouseHelper {
  protected:
    wxHtmlWindowMouseHelper( wxHtmlWindowInterface *iface );
    virtual ~wxHtmlWindowMouseHelper() { }

    /// Returns true if the mouse moved since the last call to HandleIdle
    bool DidMouseMove() const { return m_tmpMouseMoved; }

    /// Call this from EVT_MOTION event handler
    void HandleMouseMoved();
    bool HandleMouseClick( wxHtmlCell *rootCell,const wxPoint& pos, const wxMouseEvent& event );
    void HandleIdle( wxHtmlCell *rootCell, const wxPoint& pos );
    virtual void OnCellMouseHover( wxHtmlCell *cell, wxCoord x, wxCoord y );
    virtual bool OnCellClicked( wxHtmlCell *cell,
                                wxCoord x, wxCoord y,
                                const wxMouseEvent& event );

  protected:
    // this flag indicates if the mouse moved (used by HandleIdle)
    bool m_tmpMouseMoved;
    // contains last link name
    wxHtmlLinkInfo *m_tmpLastLink;
    // contains the last (terminal) cell which contained the mouse
    wxHtmlCell *m_tmpLastCell;

  private:
    wxHtmlWindowInterface *m_interface;
};

class wxHtmlWindow : public wxScrolledWindow,
  public wxHtmlWindowInterface,
  public wxHtmlWindowMouseHelper {
    DECLARE_DYNAMIC_CLASS( wxHtmlWindow )
    friend class wxHtmlWinModule;

  public:
    wxHtmlWindow() : wxHtmlWindowMouseHelper( this ) { Init(); }
    wxHtmlWindow( wxWindow *parent, wxWindowID id = wxID_ANY,
                  const wxPoint& pos = wxDefaultPosition,
                  const wxSize& size = wxDefaultSize,
                  long style = wxHW_DEFAULT_STYLE,
                  const wxString& name = wxT( "htmlWindow" ) )
      : wxHtmlWindowMouseHelper( this ) {
      Init();
      Create( parent, id, pos, size, style, name );
    }
    virtual ~wxHtmlWindow();

    bool Create( wxWindow *parent, wxWindowID id = wxID_ANY,const wxPoint& pos = wxDefaultPosition,
                 const wxSize& size = wxDefaultSize,long style = wxHW_SCROLLBAR_AUTO,
                 const wxString& name = wxT( "htmlWindow" ) );
    virtual bool SetPage( const wxString& source );

    // Append to current page
    bool AppendToPage( const wxString& source );
    virtual bool LoadPage( const wxString& location );

    // Loads HTML page from file
    bool LoadFile( const wxFileName& filename );

    // Returns full location of opened page
    wxString GetOpenedPage() const {return m_OpenedPage;}
    // Returns anchor within opened page
    wxString GetOpenedAnchor() const {return m_OpenedAnchor;}
    // Returns <TITLE> of opened page or empty string otherwise
    wxString GetOpenedPageTitle() const {return m_OpenedPageTitle;}

    // Sets frame in which page title will  be displayed. Format is format of
    // frame title, e.g. "HtmlHelp : %s". It must contain exactly one %s
    void SetRelatedFrame( wxFrame* frame, const wxString& format );
    wxFrame* GetRelatedFrame() const {return m_RelatedFrame;}

    #if wxUSE_STATUSBAR
    // After(!) calling SetRelatedFrame, this sets statusbar slot where messages
    // will be displayed. Default is -1 = no messages.
    void SetRelatedStatusBar( int bar );
    #endif // wxUSE_STATUSBAR

    void SetFonts( const wxString& normal_face, const wxString& fixed_face,const int *sizes = NULL );
    void SetStandardFonts( int size = -1,const wxString& normal_face = wxEmptyString,
                           const wxString& fixed_face = wxEmptyString );
    void SetBorders( int b ) {m_Borders = b;}
    void SetBackgroundImage( const wxBitmap& bmpBg ) { m_bmpBg = bmpBg; }
    virtual void ReadCustomization( wxConfigBase *cfg, wxString path = wxEmptyString );
    // ...
    virtual void WriteCustomization( wxConfigBase *cfg, wxString path = wxEmptyString );

    // Goes to previous/next page (in browsing history)
    // Returns true if successful, false otherwise
    bool HistoryBack();
    bool HistoryForward();
    bool HistoryCanBack();
    bool HistoryCanForward();
    // Resets history
    void HistoryClear();

    // Returns pointer to conteiners/cells structure.
    // It should be used ONLY when printing
    wxHtmlContainerCell* GetInternalRepresentation() const {return m_Cell;}

    // Adds input filter
    static void AddFilter( wxHtmlFilter *filter );

    // Returns a pointer to the parser.
    wxHtmlWinParser *GetParser() const { return m_Parser; }

    // Adds HTML processor to this instance of wxHtmlWindow:
    void AddProcessor( wxHtmlProcessor *processor );
    // Adds HTML processor to wxHtmlWindow class as whole:
    static void AddGlobalProcessor( wxHtmlProcessor *processor );
    virtual void OnSetTitle( const wxString& title );

    // Called when user clicked on hypertext link. Default behavior is to
    // call LoadPage(loc)
    virtual void OnLinkClicked( const wxHtmlLinkInfo& link );
    virtual wxHtmlOpeningStatus OnOpeningURL( wxHtmlURLType ( type ),
        const wxString& ( url ),
        wxString *( redirect ) ) const
    { return wxHTML_OPEN; }

    #if wxUSE_CLIPBOARD
    // Helper functions to select parts of page:
    void SelectWord( const wxPoint& pos );
    void SelectLine( const wxPoint& pos );
    void SelectAll();

    // Convert selection to text:
    wxString SelectionToText() { return DoSelectionToText( m_selection ); }

    // Converts current page to text:
    wxString ToText();
    #endif // wxUSE_CLIPBOARD

    virtual void OnInternalIdle();
    static wxCursor GetDefaultHTMLCursor( HTMLCursor type );
  protected:
    void Init();
    bool ScrollToAnchor( const wxString& anchor );
    void CreateLayout();
    void OnEraseBackground( wxEraseEvent& event );
    void OnPaint( wxPaintEvent& event );
    void OnSize( wxSizeEvent& event );
    void OnMouseMove( wxMouseEvent& event );
    void OnMouseDown( wxMouseEvent& event );
    void OnMouseUp( wxMouseEvent& event );
    #if wxUSE_CLIPBOARD
    void OnKeyUp( wxKeyEvent& event );
    void OnDoubleClick( wxMouseEvent& event );
    void OnCopy( wxCommandEvent& event );
    void OnClipboardEvent( wxClipboardTextEvent& event );
    void OnMouseEnter( wxMouseEvent& event );
    void OnMouseLeave( wxMouseEvent& event );
    void OnMouseCaptureLost( wxMouseCaptureLostEvent& event );
    #endif // wxUSE_CLIPBOARD

    // Returns new filter (will be stored into m_DefaultFilter variable)
    virtual wxHtmlFilter *GetDefaultFilter() {return new wxHtmlFilterPlainText;}
    static void CleanUpStatics();
    bool IsSelectionEnabled() const;

    enum ClipboardType {
      Primary,
      Secondary
    };
    bool CopySelection( ClipboardType t = Secondary );

    #if wxUSE_CLIPBOARD
    // Automatic scrolling during selection:
    void StopAutoScrolling();
    #endif // wxUSE_CLIPBOARD

    wxString DoSelectionToText( wxHtmlSelection *sel );

  public:
    // wxHtmlWindowInterface methods:
    virtual void SetHTMLWindowTitle( const wxString& title );
    virtual void OnHTMLLinkClicked( const wxHtmlLinkInfo& link );
    virtual wxHtmlOpeningStatus OnHTMLOpeningURL( wxHtmlURLType type,
        const wxString& url,
        wxString *redirect ) const;
    virtual wxPoint HTMLCoordsToWindow( wxHtmlCell *cell,
                                        const wxPoint& pos ) const;
    virtual wxWindow* GetHTMLWindow();
    virtual wxColour GetHTMLBackgroundColour() const;
    virtual void SetHTMLBackgroundColour( const wxColour& clr );
    virtual void SetHTMLBackgroundImage( const wxBitmap& bmpBg );
    virtual void SetHTMLStatusText( const wxString& text );
    virtual wxCursor GetHTMLCursor( HTMLCursor type ) const;

    // implementation of SetPage()
    bool DoSetPage( const wxString& source );

  protected:
    wxHtmlContainerCell *m_Cell;
    wxHtmlWinParser *m_Parser;
    wxString m_OpenedPage;
    wxString m_OpenedAnchor;
    wxString m_OpenedPageTitle;
    wxFileSystem* m_FS;

    wxFrame *m_RelatedFrame;
    wxString m_TitleFormat;
    #if wxUSE_STATUSBAR
    // frame in which page title should be displayed & number of it's statusbar
    // reserved for usage with this html window
    int m_RelatedStatusBar;
    #endif // wxUSE_STATUSBAR

    // borders (free space between text and window borders)
    // defaults to 10 pixels.
    int m_Borders;

    // current text selection or NULL
    wxHtmlSelection *m_selection;

    // true if the user is dragging mouse to select text
    bool m_makingSelection;

    #if wxUSE_CLIPBOARD
    wxMilliClock_t m_lastDoubleClick;
    wxHtmlWinAutoScrollTimer *m_timerAutoScroll;
    #endif // wxUSE_CLIPBOARD

  private:
    wxBitmap *m_backBuffer;
    wxBitmap m_bmpBg;
    wxPoint     m_tmpSelFromPos;
    wxHtmlCell *m_tmpSelFromCell;
    int m_tmpCanDrawLocks;
    static wxList m_Filters;
    static wxHtmlFilter *m_DefaultFilter;
    wxHtmlProcessorList *m_Processors;
    static wxHtmlProcessorList *m_GlobalProcessors;
    wxHtmlHistoryArray *m_History;
    int m_HistoryPos;
    bool m_HistoryOn;
    bool m_eraseBgInOnPaint;
    static wxCursor *ms_cursorLink;
    static wxCursor *ms_cursorText;
    DECLARE_EVENT_TABLE()
    DECLARE_NO_COPY_CLASS( wxHtmlWindow )
};

BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EXPORTED_EVENT_TYPE( wxEVT_COMMAND_HTML_CELL_CLICKED, 1000 )
DECLARE_EXPORTED_EVENT_TYPE( wxEVT_COMMAND_HTML_CELL_HOVER, 1001 )
DECLARE_EXPORTED_EVENT_TYPE( wxEVT_COMMAND_HTML_LINK_CLICKED, 1002 )
END_DECLARE_EVENT_TYPES()

class wxHtmlCellEvent : public wxCommandEvent {
  public:
    wxHtmlCellEvent() {}
    wxHtmlCellEvent( wxEventType commandType, int id,wxHtmlCell *cell, const wxPoint &pt,const wxMouseEvent &ev )
      : wxCommandEvent( commandType, id ) {
      m_cell = cell;
      m_pt = pt;
      m_mouseEvent = ev;
      m_bLinkWasClicked = false;
    }

    wxHtmlCell* GetCell() const { return m_cell; }
    wxPoint GetPoint() const { return m_pt; }
    wxMouseEvent GetMouseEvent() const { return m_mouseEvent; }

    void SetLinkClicked( bool linkclicked ) { m_bLinkWasClicked = linkclicked; }
    bool GetLinkClicked() const { return m_bLinkWasClicked; }

    // default copy ctor, assignment operator and dtor are ok
    virtual wxEvent *Clone() const { return new wxHtmlCellEvent( *this ); }

  private:
    wxHtmlCell *m_cell;
    wxMouseEvent m_mouseEvent;
    wxPoint m_pt;

    bool m_bLinkWasClicked;

    DECLARE_DYNAMIC_CLASS_NO_ASSIGN( wxHtmlCellEvent )
};

class wxHtmlLinkEvent : public wxCommandEvent {
  public:
    wxHtmlLinkEvent() {}
    wxHtmlLinkEvent( int id, const wxHtmlLinkInfo &linkinfo )
      : wxCommandEvent( wxEVT_COMMAND_HTML_LINK_CLICKED, id ) {
      m_linkInfo = linkinfo;
    }

    const wxHtmlLinkInfo &GetLinkInfo() const { return m_linkInfo; }

    // default copy ctor, assignment operator and dtor are ok
    virtual wxEvent *Clone() const { return new wxHtmlLinkEvent( *this ); }

  private:
    wxHtmlLinkInfo m_linkInfo;

    DECLARE_DYNAMIC_CLASS_NO_ASSIGN( wxHtmlLinkEvent )
};


typedef void ( wxEvtHandler::*wxHtmlCellEventFunction )( wxHtmlCellEvent& );
typedef void ( wxEvtHandler::*wxHtmlLinkEventFunction )( wxHtmlLinkEvent& );

#define wxHtmlCellEventHandler(func) \
  (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxHtmlCellEventFunction, &func)
#define wxHtmlLinkEventHandler(func) \
  (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxHtmlLinkEventFunction, &func)

#define EVT_HTML_CELL_CLICKED(id, fn) \
  wx__DECLARE_EVT1(wxEVT_COMMAND_HTML_CELL_CLICKED, id, wxHtmlCellEventHandler(fn))
#define EVT_HTML_CELL_HOVER(id, fn) \
  wx__DECLARE_EVT1(wxEVT_COMMAND_HTML_CELL_HOVER, id, wxHtmlCellEventHandler(fn))
#define EVT_HTML_LINK_CLICKED(id, fn) \
  wx__DECLARE_EVT1(wxEVT_COMMAND_HTML_LINK_CLICKED, id, wxHtmlLinkEventHandler(fn))

#endif
